#include <stx/test/test.hpp>

void check__(std::string_view const sv_jsn)
{
    auto parser = JsonParser{};

    CHECK(parser.parse(sv_jsn));
    auto opt = parser.getValue(""sv);
    CHECK(opt);
    CHECK(opt->isObject());

    CHECK(parser.getValue("/k1"sv)->isInt64());
    CHECK(1 == parser.getValue("/k1"sv)->getInt64());
    CHECK(parser.getValue("/k2"sv)->isArray());
    CHECK(parser.getValue("/k3"sv)->isObject());
    CHECK(parser.getValue("/k3/k31"sv)->isInt64());
    CHECK(4 == parser.getValue("/k3/k31"sv)->getInt64());
    CHECK(parser.getValue("/k3/k32"sv)->isArray());
    CHECK(parser.getValue("/k3/k32/0"sv)->isString());
    CHECK(parser.getValue("/k3/k32/1"sv)->isNull());
    CHECK(parser.getValue("/k3/k32/2"sv)->isBool());
    CHECK(parser.getValue("/k3/k32/3"sv)->isBool());
    CHECK(parser.getValue("/k3/k32/4"sv)->isInt64());
    CHECK(parser.getValue("/k3/k32/5"sv)->isDouble());
    CHECK(parser.getValue("/k3/k32/6"sv)->isInt64());
    CHECK(parser.getValue("/k3/k32/7"sv)->isDouble());
    CHECK(parser.getValue("/k3/k32/8"sv)->isArray());
    CHECK(parser.getValue("/k3/k32/9"sv)->isObject());
    CHECK(parser.getValue("/k4"sv)->isNull());
    CHECK(parser.getValue("/k5"sv)->isString());
    CHECK(parser.getValue("/k5"sv)->getString() == "hello"sv);
    CHECK(parser.getValue("/k6"sv)->isDouble());
    CHECK(parser.getValue("/k6"sv)->getDouble() > 3.14158);
    CHECK(parser.getValue("/k7"sv)->isBool());
    CHECK(parser.getValue("/k7"sv)->getBool() == true);
    CHECK(parser.getValue("/k8"sv)->isBool());
    CHECK(parser.getValue("/k8"sv)->getBool() == false);

    for (auto const& [key, value] :
         getJsonObject(*parser.getValue("/k3/k32/9"sv)))
    {
        CHECK(value.isString());
    }

    for (auto const& value : getJsonArray(*parser.getValue("/k3/k32/8"sv)))
    {
        CHECK(value.isInt64());
    }
}

TEST_CASE (core_json)
{
    auto const sv_jsn = R"(
{
	"k1": 1, 
	"k2": [6, 7, 8], 
	"k3": {
		"k31": 4, 
		"k32": [
			"hello", 
			null, 
			true, 
			false,
			23, 
			3.14159, 
			-23, 
			-3.14159,
			[1, 2, 3],
			{
				"k321": "bill",
				"k322": "gates"
			}]
		},
	"k4": null,
	"k5": "hello",
	"k6": 3.14159,
	"k7": true,
	"k8": false
})"sv;

    check__(sv_jsn);

    auto s_jsn = std::string{};

    {
        auto parser = JsonParser{};
        CHECK(parser.parse(sv_jsn));
        check__(JsonBuilderNode(*parser.getValue(""sv)).dump());

        auto jbn   = JsonBuilderNode(*parser.getValue(""sv));
        auto opt_v = jbn["k3"sv].extract("k31"sv);
        CHECK(opt_v);
        jbn["k9"sv] = opt_v->get();
        jbn["k3"sv].erase("k32"sv);
        jbn["k2"sv].append(2.718);
        jbn["k2"sv].append(true);
        jbn["k3"sv]["k33"s] = "clinton"s;
        s_jsn               = jbn.dump();
    }

    {
        auto parser = JsonParser{};
        CHECK(parser.parse(s_jsn));
        CHECK(!parser.getValue("/k3/k32"sv));
        CHECK(parser.getValue("/k3/k33"sv)->isString());
        CHECK(parser.getValue("/k3/k33"sv)->getString() == "clinton"sv);
        CHECK(parser.getValue("/k2/3"sv)->isDouble());
        CHECK(parser.getValue("/k2/3"sv)->getDouble() >= 2.717);
        CHECK(parser.getValue("/k2/4"sv)->isBool());
        CHECK(parser.getValue("/k2/4"sv)->getBool() == true);
        CHECK(parser.getValue("/k9"sv)->isInt64());
        CHECK(parser.getValue("/k9"sv)->getInt64() == 4);
    }
}